﻿using Ninject;
//using Nx.Navigation;
using Nx.UI.Navigation;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Nx.Modules
{
#if SILVERLIGHT || WINDOWS_PHONE || NETFX_CORE
    public abstract class Module<TNavEnum> : Nx.Modules.Module
    {
        public Module()
        {
        }

        public virtual IEnumerable<NavigationLink> NavigationLinks
        {
            get
            {
                return Enumerable.Empty<NavigationLink>();
            }
        }

        public virtual IEnumerable<ISetting> Modulesettings
        {
            get
            {
                return Enumerable.Empty<ISetting>();
            }
        }


        public override void Load()
        {
            this.Kernel.Bind<INavigationModel<TNavEnum>>().To<NavigationModel<TNavEnum>>().InSingletonScope();
            this.NavigationModel = Kernel.Get<INavigationModel<TNavEnum>>();

            base.Load();

            ModuleLogger.Info("Configuring navigation...");
            ConfigureNavigation();
            ModuleLogger.Info("Loaded");
        }

        private void ConfigureNavigation()
        {
#if !NETFX_CORE && (SILVERLIGHT && !WINDOWS_PHONE)
                UriMapper mapper = (UriMapper)Application.Current.Resources["uriMapper"];
#endif

            foreach (var navigationLink in this.NavigationLinks)
            {
                #region Register in the NavigationModel
                var navLinkType = navigationLink.GetType();

#if!NETFX_CORE
                if (navLinkType.IsGenericType)
                {
                    Type[] genericTypes = navLinkType.GetGenericArguments();
#else
                if (navLinkType.IsConstructedGenericType)
                {
                    Type[] genericTypes = navLinkType.GenericTypeArguments;
#endif

                    if (genericTypes.Length == 1)
                    {
                        NavigationModel.Register((navigationLink as NavigationLink<TNavEnum>).Type, navigationLink.NavigationTarget);
                    }
                    else if (genericTypes.Length == 2)
                    {
                        Type viewModelType = genericTypes[1];
                        NavigationModel.Register((navigationLink as NavigationLink<TNavEnum>).Type, viewModelType, navigationLink.NavigationTarget);
                    }
                }
                #endregion

#if !NETFX_CORE && (SILVERLIGHT && !WINDOWS_PHONE)
                #region CreateUriMapping
                    mapper.UriMappings.Insert(0, navigationLink.UriMapping);
                #endregion
#endif
            }
        }

#if !NETFX_CORE && (SILVERLIGHT && !WINDOWS_PHONE)
            protected T InitDomainContext<T>(string riaServiceSvcFileName)
                where T : DomainContext
            {
                ConstructorInfo constructor = null;

                if (this.IsRemoteModule)
                {
                    constructor = typeof(T).GetConstructor(new Type[] { typeof(Uri) });
                }
                else
                {
                    constructor = typeof(T).GetConstructor(new Type[] { });
                }

                return (this.IsRemoteModule ? constructor.Invoke(new object[] { new Uri(string.Format(CultureInfo.InvariantCulture, "{0}{1}", this.ModuleOrigin, riaServiceSvcFileName)) })
                    : constructor.Invoke(new object[] { })) as T;
            }

            public bool IsRemoteModule
            {
                get
                {
                    return ModuleInfo != null ?
                        ModuleInfo.Ref.StartsWith("hICodep://", StringComparison.OrdinalIgnoreCase) : false;
                }
            }

            public string ModuleOrigin
            {
                get
                {
                    if (IsRemoteModule)
                    {
                        return string.Format(CultureInfo.InvariantCulture, "{0}ClientBin/",
                            ModuleInfo.Ref.Substring(0, ModuleInfo.Ref.IndexOf("ClientBin", StringComparison.OrdinalIgnoreCase)));
                    }
                    else
                    {
                        return string.Empty;
                    }
                }
            }
#endif

        public override void OnDisposing()
        {
            if (this.NavigationModel != null)
            {
                this.NavigationModel.Dispose();
                this.NavigationModel = null;
            }

#if !NETFX_CORE && (SILVERLIGHT && !WINDOWS_PHONE)
                UriMapper mapper = (UriMapper)Application.Current.Resources["uriMapper"];

                foreach (var link in this.NavigationLinks)
                {
                    mapper.UriMappings.Remove(link.UriMapping);
                }
#endif
        }

        public INavigationModel<TNavEnum> NavigationModel { get; private set; }
    }
#endif
}
